#include "listbuffer.hpp"
#include "streamer.hpp"

#include "cmd_value.hpp"
#include "confsvr_cmd.hpp"
#include "db_cmd.hpp"
#include "balance_cmd.hpp"
#include "gateway_cmd.hpp"
#include "scence_cmd.hpp"

#include "cmd_parser.hpp"

namespace cmd
{
	int CmdParser::encode(ListBuffer & listbuffer, void * data)
	{
		CmdHead & cmd = *(CmdHead*)data;

		Streamer streamer(Streamer::ISTREAMER, listbuffer);

		uint32_t type = cmd.cmd_type();

#define USE_SWITCH

#define CMD_DISPATCH(class, cmd_0, cmd_1) \
		case MakeUint32_t<cmd_0, cmd_1>::value: \
		{ 	\
			streamer & (*(class*)&cmd); \
			\
			return 0; \
		} \
		break;
	
#include "cmd.def"

#undef CMD_DISPATCH

#undef USE_SWITCH
		return -1;
	}


#define CMD_HEADER_VALUE(pos, type) \
	{ \
		if ((uint32_t)listbuffer.bytes_consumable() < CmdHead::LENGTH) \
		{ \
			return (type)-1; \
		} \
	\
		type value = 0; \
		listbuffer.copy_out(value, pos); \
		return value; \
	}

	int CmdParser::decode(ListBuffer & listbuffer, void *& data)
	{
		if (!frame(listbuffer))
		{
			return 0;
		}

		Streamer streamer(Streamer::OSTREAMER, listbuffer);
	
		uint16_t cmd_0 = get_cmd_0(listbuffer);
		uint16_t cmd_1 = get_cmd_1(listbuffer);
		
		uint32_t type = (((uint32_t)cmd_0) << 16) | ((uint32_t)cmd_1);

#define USE_SWITCH

#define CMD_DISPATCH(class, cmd_0, cmd_1) \
		case MakeUint32_t<cmd_0, cmd_1>::value: \
		{ \
			class * cmd  = new (_buffer) class; \
		\
			streamer & (*(class*)cmd); \
		\
			data             = cmd; \
		\
			return 0; \
		}

#include "cmd.def"

#undef CMD_CMD

#undef USE_SWITCH

		return -1;
	}
	
	bool CmdParser::frame(ListBuffer & listbuffer)
	{
		return (get_length(listbuffer) <= (uint32_t)listbuffer.bytes_consumable());
	}
	
	uint32_t CmdParser::get_magic(ListBuffer & listbuffer)
	{
		CMD_HEADER_VALUE(CmdHead::MAGIC_POS, uint32_t);
	}

	uint32_t CmdParser::get_length(ListBuffer & listbuffer)
	{
		CMD_HEADER_VALUE(CmdHead::LENGTH_POS, uint32_t);
	}

	cmd_0_type CmdParser::get_cmd_0(ListBuffer & listbuffer)
	{
		CMD_HEADER_VALUE(CmdHead::CMD_0_POS, cmd_0_type);
	}

	cmd_1_type CmdParser::get_cmd_1(ListBuffer & listbuffer)
	{
		CMD_HEADER_VALUE(CmdHead::CMD_1_POS, cmd_1_type);
	}

#undef CMD_HEADER_VALUE
};

